home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
msysjour
/
vol06
/
03
/
wintro6
/
graph.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-01
|
20KB
|
616 lines
/*=================================================================*/
/* */
/* File : GRAPH.C */
/* */
/* Purpose : Render the graphs for the stock charts */
/* */
/* History : */
/* */
/* (C) Copyright 1989,1990 Marc Adler/Magma Systems */
/*=================================================================*/
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include "stock.h"
void FAR PASCAL HandleSelectionState(LPDRAWITEMSTRUCT lpdis,
int inflate);
void FAR PASCAL HandleFocusState(LPDRAWITEMSTRUCT lpdis,
int inflate);
void FAR PASCAL DrawEntireItem(LPDRAWITEMSTRUCT lpdis,
int inflate);
BOOL FAR PASCAL
GraphOptionsDlgProc(hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{
int iPen;
char szBuf[80];
static HANDLE hStockInfo = NULL;
static LPSTOCKINFO lpStockInfo = (LPSTOCKINFO) NULL;
LPGRAPHINFO lpGraphInfo;
HWND hWnd;
BOOL bTranslated;
switch (message)
{
case WM_INITDIALOG :
if ((hStockInfo = (HANDLE) lParam) == NULL)
{
EndDialog(hDlg, IDCANCEL);
return TRUE;
}
if ((lpStockInfo = (LPSTOCKINFO) GlobalLock(hStockInfo)) == NULL)
{
EndDialog(hDlg, IDCANCEL);
return TRUE;
}
lpGraphInfo = &lpStockInfo->StockFile.graphinfo;
/*
If the ticks array has some memory allocated to it, it means
that we are dealing with an existing stock. If not, then we
are creating a new stock.
*/
if (lpStockInfo->hTicks != NULL)
{
SetDlgItemText(hDlg, ID_SYMBOL,
lpStockInfo->StockFile.szStock);
SetDlgItemInt(hDlg, ID_MINPRICE,
(int) lpGraphInfo->dwMinPrice, FALSE);
SetDlgItemInt(hDlg, ID_MAXPRICE,
(int) lpGraphInfo->dwMaxPrice, FALSE);
SetDlgItemInt(hDlg, ID_FACTOR,
(int)lpGraphInfo->dwScaleFactor,FALSE);
SetDlgItemInt(hDlg, ID_TICKINT,
(int)lpGraphInfo->dwTickInterval,FALSE);
SetDlgItemInt(hDlg, ID_DENOMINATOR,
(int) lpGraphInfo->iDenominator, FALSE);
if (lpStockInfo->dwFlags & STATE_HAS_VGRID)
CheckDlgButton(hDlg, ID_VERTGRID, TRUE);
if (lpStockInfo->dwFlags & STATE_HAS_HGRID)
CheckDlgButton(hDlg, ID_HORZGRID, TRUE);
EnableWindow(GetDlgItem(hDlg, ID_SYMBOL), FALSE);
}
else
{
lpGraphInfo->iGridPen = 0;
}
/*
Fill the listbox with pen ids
*/
for (iPen = 0; iPen < PS_NULL; iPen++)
SendDlgItemMessage(hDlg, ID_GRIDSTYLE, CB_ADDSTRING, 0,
(LONG) iPen);
SendDlgItemMessage(hDlg,ID_GRIDSTYLE,CB_SETCURSEL,
lpGraphInfo->iGridPen,0L);
return TRUE;
case WM_MEASUREITEM :
{
LPMEASUREITEMSTRUCT lpMI = (LPMEASUREITEMSTRUCT)(LPSTR)lParam;
lpMI->itemWidth = 42;
lpMI->itemHeight = 20;
break;
}
case WM_DRAWITEM :
{
LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) (LPSTR) lParam;
if (lpdis->itemID == -1)
{
HandleFocusState(lpdis, -5);
break;
}
switch (lpdis->itemAction)
{
case ODA_DRAWENTIRE:
DrawEntireItem(lpdis, -4);
break;
case ODA_SELECT:
HandleSelectionState(lpdis, 0);
break;
case ODA_FOCUS:
HandleFocusState(lpdis, -2);
break;
}
break;
}
case WM_COMMAND :
switch (wParam)
{
case IDOK :
lpGraphInfo = &lpStockInfo->StockFile.graphinfo;
if (lpStockInfo->hTicks == NULL)
{
GetDlgItemText(hDlg, ID_SYMBOL, szBuf, sizeof(szBuf));
if (*szBuf == '\0')
{
MessageBox(hWndMain,
"You must fill in the name of the stock.",
"Error", MB_OK);
return TRUE;
}
strcat(szBuf, ".STO");
lstrcpy(lpStockInfo->szFileName, szBuf);
lpStockInfo->StockFile.dwMagic = MAGIC_COOKIE;
if ((lpStockInfo->hTicks = GlobalAlloc(GMEM_MOVEABLE,
(DWORD) sizeof(TICK) * 64)) == NULL)
{
MessageBox(hWndMain, "Can't allocate the ticker array",
"Error", MB_OK);
goto bye;
}
lpStockInfo->nTicksAllocated = 64;
lpStockInfo->StockFile.nTicks = 0;
/*
Create a window for this guy
*/
hWnd = lpStockInfo->hWnd =
GraphCreateWindow((LPSTR) szBuf);
SetWindowWord(lpStockInfo->hWnd, 0, hStockInfo);
lpStockInfo->dwFlags |= STATE_DIRTY;
}
GetDlgItemText(hDlg, ID_SYMBOL,
lpStockInfo->StockFile.szStock,
sizeof(lpStockInfo->StockFile.szStock));
lpGraphInfo->dwMinPrice =
GetDlgItemLong(hDlg, ID_MINPRICE,
(BOOL FAR *) &bTranslated, FALSE);
lpGraphInfo->dwMaxPrice =
GetDlgItemLong(hDlg, ID_MAXPRICE,
(BOOL FAR *) &bTranslated, FALSE);
lpGraphInfo->dwScaleFactor =
GetDlgItemLong(hDlg, ID_FACTOR,
(BOOL FAR *) &bTranslated, FALSE);
lpGraphInfo->dwTickInterval =
GetDlgItemLong(hDlg, ID_TICKINT,
(BOOL FAR *) &bTranslated, FALSE);
lpGraphInfo->iDenominator =
GetDlgItemInt(hDlg, ID_DENOMINATOR,
(BOOL FAR *) &bTranslated, FALSE);
lpGraphInfo->iGridPen = (WORD)
SendDlgItemMessage(hDlg,ID_GRIDSTYLE,CB_GETCURSEL,0,0L);
lpStockInfo->dwFlags &= ~(STATE_HAS_VGRID|STATE_HAS_HGRID);
if (IsDlgButtonChecked(hDlg, ID_VERTGRID))
lpStockInfo->dwFlags |= STATE_HAS_VGRID;
if (IsDlgButtonChecked(hDlg, ID_HORZGRID))
lpStockInfo->dwFlags |= STATE_HAS_HGRID;
bye:
InvalidateRect(lpStockInfo->hWnd, (LPRECT) NULL, FALSE);
GlobalUnlock(hStockInfo);
EndDialog(hDlg, IDOK);
break;
case IDCANCEL:
GlobalUnlock(hStockInfo);
EndDialog(hDlg, IDCANCEL);
break;
}
return TRUE;
} /* end switch (message) */
return FALSE;
}
/****************************************************************************
* *
* FUNCTION : HandleSelectionState(LPDRAWITEMSTRUCT, int) *
* *
* PURPOSE : Handles a change in an item selection state. If an item is *
* selected, a black rectangular frame is drawn around that *
* item; if an item is de-selected, the frame is removed. *
* *
* COMMENT : The black selection frame is slightly larger than the gray *
* focus frame so they won't paint over each other. *
* *
****************************************************************************/
void FAR PASCAL HandleSelectionState(lpdis, inflate)
LPDRAWITEMSTRUCT lpdis;
int inflate;
{
HBRUSH hbr = (lpdis->itemState & ODS_SELECTED) ?
GetStockObject(BLACK_BRUSH) :
CreateSolidBrush(GetSysColor(COLOR_WINDOW));
FrameRect(lpdis->hDC, (LPRECT) &lpdis->rcItem, hbr);
DeleteObject (hbr);
}
/****************************************************************************
* *
* FUNCTION : HandleFocusState(LPDRAWITEMSTRUCT, int) *
* *
* PURPOSE : Handle a change in item focus state. If an item gains the *
* input focus, a gray rectangular frame is drawn around that *
* item; if an item loses the input focus, the gray frame is *
* removed. *
* *
* COMMENT : The gray focus frame is slightly smaller than the black *
* selection frame so they won't paint over each other. *
* *
****************************************************************************/
void FAR PASCAL HandleFocusState(lpdis, inflate)
LPDRAWITEMSTRUCT lpdis;
int inflate;
{
RECT rc;
HBRUSH hbr;
/* Resize rectangle to place focus frame between the selection
* frame and the item.
*/
CopyRect ((LPRECT)&rc, (LPRECT)&lpdis->rcItem);
InflateRect ((LPRECT)&rc, inflate, inflate);
if (lpdis->itemState & ODS_FOCUS)
/* gaining input focus -- paint a gray frame */
hbr = GetStockObject(GRAY_BRUSH);
else
/* losing input focus -- remove (paint over) frame */
hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
FrameRect(lpdis->hDC, (LPRECT)&rc, hbr);
DeleteObject (hbr);
}
/********************************************************************
* *
* FUNCTION : DrawEntireItem(LPDRAWITEMSTRUCT, int) *
* *
* PURPOSE : Draws an item and frames it with a selection frame *
and/or a focus frame when appropriate. *
* *
*******************************************************************/
void FAR PASCAL DrawEntireItem(lpdis, inflate)
LPDRAWITEMSTRUCT lpdis;
int inflate;
{
RECT rc;
HANDLE hOldPen;
HPEN hPen;
if (lpdis->itemData < 0)
return;
/* Resize rectangle to leave space for frames */
CopyRect ((LPRECT)&rc, (LPRECT)&lpdis->rcItem);
InflateRect ((LPRECT)&rc, inflate, inflate);
if (lpdis->itemState & ODS_FOCUS)
hPen = CreatePen((int)lpdis->itemData, 1, RGB(0xFF, 0xFF, 0xFF));
else
hPen = CreatePen((int) lpdis->itemData, 1, RGB(0, 0, 0));
hOldPen = SelectObject(lpdis->hDC, hPen);
MoveTo(lpdis->hDC, rc.left, rc.top + (rc.bottom - rc.top) / 2);
LineTo(lpdis->hDC, rc.right, rc.top + (rc.bottom - rc.top) / 2);
SelectObject(lpdis->hDC, hOldPen);
DeleteObject(hPen);
/* Draw or erase appropriate frames */
HandleSelectionState(lpdis, inflate + 4);
HandleFocusState(lpdis, inflate + 2);
}
int PASCAL GraphWndPaint(HWND hWnd, HDC hDC, LPSTOCKINFO lpStockInfo, BOOL bPrinting)
{
RECT r;
int i, x, y;
int xGraph, yGraph;
LPTICK lpTick;
int rangeHigh,
rangeLow,
xPixelsPerDate,
yTickInterval;
int yAxisStart, xAxisStart;
HANDLE hOldPen;
HPEN hPen;
HBRUSH hBrush;
HFONT hFont, hOldFont;
TEXTMETRIC tm;
char szBuf[80];
if (lpStockInfo->StockFile.nTicks == 0)
return TRUE;
if ((lpTick = (LPTICK) GlobalLock(lpStockInfo->hTicks)) == NULL)
return TRUE;
/*
Get the client dimensions of the current stock window and figure
out the width and height of the graph.
*/
if (bPrinting)
{
yGraph = GetDeviceCaps(hDC, VERTRES);
xGraph = GetDeviceCaps(hDC, HORZRES);
}
else
{
GetClientRect(hWnd, (LPRECT) &r);
yGraph = r.bottom - r.top;
xGraph = r.right - r.left;
}
/*
Erase the background to the desired color
*/
if (!bPrinting)
{
hBrush = CreateSolidBrush(lpStockInfo->graphAttrs.clrBackground);
FillRect(hDC, (LPRECT) &r, hBrush);
DeleteObject(hBrush);
}
/*
Get the low and high range into local variables.
*/
rangeHigh = (int) lpStockInfo->StockFile.graphinfo.dwMaxPrice;
rangeLow = (int) lpStockInfo->StockFile.graphinfo.dwMinPrice;
if ((yTickInterval =
(int) lpStockInfo->StockFile.graphinfo.dwTickInterval) < 1)
yTickInterval = 1;
/*
Get the metrics of the current font.
*/
hOldFont = NULL;
if (lpStockInfo->graphAttrs.hFont)
hOldFont = SelectObject(hDC, lpStockInfo->graphAttrs.hFont);
GetTextMetrics(hDC, (LPTEXTMETRIC) &tm);
/*
Set up the mapping mode. Y-axis points up and X-axis points right.
*/
SetMapMode(hDC, lpStockInfo->graphAttrs.iMappingMode);
SetWindowExt(hDC, xGraph, yGraph);
SetViewportExt(hDC, xGraph, -yGraph);
SetViewportOrg(hDC, 0, yGraph);
sprintf(szBuf, "%d", rangeHigh);
yAxisStart = strlen(szBuf) * (tm.tmAveCharWidth + 1);
xAxisStart = tm.tmHeight + (tm.tmHeight/2);
xPixelsPerDate = xGraph / lpStockInfo->StockFile.nTicks;
/*
Set the background drawing mode to TRANSPARENT so that the spaces
in between the letters and grid lines get filled with the
background color.
*/
SetBkMode(hDC, TRANSPARENT);
/*
Draw the axises. First the Y-axis, then the X-axis.
*/
MoveTo(hDC, yAxisStart, xAxisStart);
LineTo(hDC, yAxisStart, yGraph);
MoveTo(hDC, yAxisStart, xAxisStart);
LineTo(hDC, xGraph, xAxisStart);
/*
Draw the hash marks for the x-axis
*/
for (i = 1; i < lpStockInfo->StockFile.nTicks; i++)
{
int x = i * xPixelsPerDate + yAxisStart;
int iTextLen;
MoveTo(hDC, x, xAxisStart-2);
LineTo(hDC, x, xAxisStart+2);
sprintf(szBuf, "%d", i+1);
iTextLen = strlen(szBuf) * tm.tmAveCharWidth;
/*
Output the x-axis text centered over the hash mark
*/
TextOut(hDC, x-(iTextLen>>1), xAxisStart-2, szBuf,strlen(szBuf));
}
/*
Draw the hash marks for the y-axis
*/
for (i = rangeLow; i <= rangeHigh;
i += yTickInterval)
{
int y = (int) ((long) (i-rangeLow) * (long) (yGraph-xAxisStart) /
(rangeHigh-rangeLow) + xAxisStart);
if (i > rangeLow)
{
MoveTo(hDC, yAxisStart-4, y);
LineTo(hDC, yAxisStart+4, y);
}
sprintf(szBuf, "%d", i);
TextOut(hDC, 0, y + (tm.tmHeight >> 1), szBuf, strlen(szBuf));
}
/*
Now draw the horizontal and vertical grid lines.
*/
hPen = CreatePen(lpStockInfo->StockFile.graphinfo.iGridPen, 1,
lpStockInfo->graphAttrs.clrPen);
hOldPen = SelectObject(hDC, hPen);
if (lpStockInfo->dwFlags & STATE_HAS_VGRID)
{
for (i = 0; i < lpStockInfo->StockFile.nTicks; i++)
{
int x = (i+1) * xPixelsPerDate + yAxisStart;
MoveTo(hDC, x, xAxisStart);
LineTo(hDC, x, yGraph);
}
}
if (lpStockInfo->dwFlags & STATE_HAS_HGRID)
{
for (i = rangeLow + yTickInterval; i <= rangeHigh;
i += yTickInterval)
{
int y = (int) ((long) (i-rangeLow) * (long) (yGraph-xAxisStart) /
(rangeHigh - rangeLow) + xAxisStart);
MoveTo(hDC, yAxisStart, y);
LineTo(hDC, xGraph, y);
}
}
SelectObject(hDC, hOldPen);
DeleteObject(hPen);
/*
Figure out how many pixels wide each entry should be. This is
equal to the width of the graph divided by the number of ticks
to be plotted.
*/
MoveTo(hDC, yAxisStart, (int) (xAxisStart +
(long) (lpTick[0].price - rangeLow) *
(long) yGraph / (rangeHigh - rangeLow)));
if (lpStockInfo->StockFile.nTicks == 1)
{
Ellipse(hDC, yAxisStart-2, xAxisStart-2,
yAxisStart+2, xAxisStart+2);
}
else
{
for (i = 1; i < lpStockInfo->StockFile.nTicks; i++)
{
int x = i * xPixelsPerDate;
int y = (int) ((lpTick[i].price - rangeLow) * (long) yGraph /
(rangeHigh-rangeLow));
LineTo(hDC, x + yAxisStart, y + xAxisStart);
Ellipse(hDC, x+yAxisStart-2, y+xAxisStart-2,
x+yAxisStart+2, y+xAxisStart+2);
}
}
if (hOldFont)
SelectObject(hDC, hOldFont);
GlobalUnlock(lpStockInfo->hTicks);
return TRUE;
}
#include "rainbow.h"
BOOL FAR PASCAL GraphColorsDlgProc(hDlg, msg, wParam, lParam)
HWND hDlg;
WORD msg;
WORD wParam;
LONG lParam;
{
LPSTOCKINFO lpStockInfo;
char szMsg[80];
switch (msg)
{
case WM_INITDIALOG:
/*
Make sure that there is a current stock information record
which we can append the ticker onto.
*/
if (!hCurrStockInfo)
{
MessageBox(hDlg, "There is no current stock graph.",
"Error", MB_OK);
EndDialog(hDlg, FALSE);
return TRUE;
}
lpStockInfo = (LPSTOCKINFO) GlobalLock(hCurrStockInfo);
if (lpStockInfo == NULL)
{
MessageBox(hDlg, "GlobalLock returned NULL", "Error", MB_OK);
EndDialog(hDlg, FALSE);
return TRUE;
}
SendDlgItemMessage(hDlg, ID_PENCOLOR, RM_SETSEL,
lpStockInfo->graphAttrs.idxPen, 0L);
SendDlgItemMessage(hDlg, ID_BACKCOLOR, RM_SETSEL,
lpStockInfo->graphAttrs.idxBackground, 0L);
GlobalUnlock(hCurrStockInfo);
return TRUE;
case WM_COMMAND:
switch (wParam)
{
/*
The user chose the OK button...
*/
case IDOK:
/*
Get a pointer to the stock info record
*/
lpStockInfo = (LPSTOCKINFO) GlobalLock(hCurrStockInfo);
if (lpStockInfo == NULL)
{
MessageBox(hDlg, "GlobalLock returned NULL",
"Error", MB_OK);
EndDialog(hDlg, FALSE);
break;
}
lpStockInfo->graphAttrs.idxPen = (WORD)
SendDlgItemMessage(hDlg, ID_PENCOLOR, RM_GETSEL, 0,
(LONG) (LPSTR) &lpStockInfo->graphAttrs.clrPen);
lpStockInfo->graphAttrs.idxBackground = (WORD)
SendDlgItemMessage(hDlg, ID_BACKCOLOR, RM_GETSEL, 0,
(LONG) (LPSTR)
&lpStockInfo->graphAttrs.clrBackground);
InvalidateRect(lpStockInfo->hWnd, (LPRECT) NULL, FALSE);
GlobalUnlock(hCurrStockInfo);
EndDialog(hDlg, TRUE);
break;
/*
The user chose the CANCEL button....
*/
case IDCANCEL :
EndDialog(hDlg, FALSE);
break;
}
return TRUE;
default:
return FALSE;
}
}